package kernel

import (
	. "data/datatype"
	"data/entity"
	"sync/atomic"
	"util/log"
	. "util/pool"
)

type objtype struct {
	typ    int
	dttype string
}

var (
	objhooker = make(map[string]objtype)
)

func RegType(t string, typ int, dttype string) bool {
	if _, dup := objhooker[t]; dup {
		panic("type already exist")
	}

	objhooker[t] = objtype{typ, dttype}
	return true
}

func Type(t string) int {
	if typ, ok := objhooker[t]; ok {
		return typ.typ
	}
	return NONE
}

type factory struct {
	pl       PoolList
	serial   int32
	delnum   int32
	kernel   interface{}
	regionid int32
}

func (f *factory) SetKernel(k interface{}) {
	f.kernel = k
}

func (f *factory) GetKernel() interface{} {
	return f.kernel
}

func (f *factory) GetCount() int {
	return f.pl.Count()
}

func (f *factory) GetObject(id ObjectID) GameObjecter {
	if id.IsNil() {
		return nil
	}

	obj := f.pl.GetObject(int(id.Index - 1))
	if obj == nil {
		return nil
	}

	if o, ok := obj.(GameObjecter); ok {
		objid := o.GetObjId()
		if objid.Serial == id.Serial {
			return o
		}
	}

	return nil
}

func (f *factory) add(obj GameObjecter) *ObjectID {
	index := f.pl.AddObject(-1, obj)

	if index == -1 {
		return nil
	}

	atomic.AddInt32(&f.serial, 1)
	if f.serial <= 0 {
		atomic.SwapInt32(&f.serial, 1)
	}

	id := ObjectID{f.regionid, int32(index + 1), f.serial}

	obj.SetObjId(id)

	return &id
}

func (f *factory) Create(t string) (GameObjecter, *ObjectID) {

	var typ objtype
	var ok bool
	if typ, ok = objhooker[t]; !ok {
		panic("type not exist")
	}

	var obj GameObjecter

	switch typ.typ {
	case SCENE:
		obj = &GameObject{}
	case NPC:
		obj = &GONpc{}
	case PLAYER:
		obj = &GOPlayer{}
	case ITEM:
		obj = &GOItem{}
	case HELPER:
		obj = &GOHelper{}
	}

	if obj == nil {
		log.LogError("create object failed, type ", t)
		return nil, nil
	}

	id := f.add(obj)

	if id == nil {
		return nil, nil
	}

	data := entity.Create(typ.dttype)
	if data == nil {
		return nil, nil
	}

	obj.SetData(data)

	return obj, id
}

//删除所有对象
func (f *factory) DeleteAll() {

	lens := f.pl.PoolLen()
	for si := 0; si < lens; si++ {
		p := f.pl.GetPool(si)
		for pi := 0; pi < p.Capacity(); pi++ {
			obj := p.GetSlot(pi)
			if obj == nil {
				continue
			}

			if o, ok := obj.(GameObjecter); ok {
				o.Delete()
				f.delnum++
			}
		}
	}
}

//删除对象，这里只设置删除标志
func (f *factory) Delete(id ObjectID) {
	if id.IsNil() {
		return
	}

	obj := f.pl.GetObject(int(id.Index - 1))
	if obj == nil {
		return
	}

	if o, ok := obj.(GameObjecter); ok {
		objid := o.GetObjId()
		if objid.Serial != id.Serial {
			log.LogError("object not found")
			return
		}
		atomic.AddInt32(&f.delnum, 1)
		o.Delete()
	}
}

//直接移除对象
func (f *factory) remove(o interface{}) {
	lens := f.pl.PoolLen()
	for si := 0; si < lens; si++ {
		p := f.pl.GetPool(si)
		for pi := 0; pi < p.Capacity(); pi++ {
			obj := p.GetSlot(pi)
			if obj == nil {
				continue
			}

			if o != obj {
				continue
			}

			if o, ok := obj.(GameObjecter); ok {
				if o.IsDel() {
					return
				}
				p.ClearSlot(pi)
				return
			}
		}
	}
}

//删除到期的对象
func (f *factory) ClearDelete() {

	if f.delnum <= 0 {
		return
	}

	lens := f.pl.PoolLen()
	for si := 0; si < lens; si++ {
		p := f.pl.GetPool(si)
		for pi := 0; pi < p.Capacity(); pi++ {
			obj := p.GetSlot(pi)
			if obj == nil {
				continue
			}

			if o, ok := obj.(GameObjecter); ok {
				if o.IsDel() {
					p.ClearSlot(pi)
					atomic.AddInt32(&f.delnum, -1)
				}
			}
		}
	}
}

func CreateFactory(regionid int32) *factory {
	f := &factory{}
	f.pl = PoolList{}
	f.regionid = regionid
	f.pl.Init(-1, 256)
	return f
}
